#include "stdafx.h"
#include "CameraSystem.h"

#include "Components\CameraComponent.h"
#include "Components\TileComponent.h"

#include "World\World.h"

#include "Utilities\CameraHelper.h"
#include "InputManager.h"

#include "Event.h"
#include "EntityEvent.h"

using namespace ZeEngine;
using namespace std;

CameraSystem::CameraSystem() : m_pGaulemEntity(NULL), 
                               m_pGaulemCamera(NULL), 
                               m_pGaulemCameraComponent(NULL),
                               m_pBaseCamera(NULL), 
                               m_pBaseCameraComponent(NULL),
                               m_fDragging(false)
{
}


CameraSystem::~CameraSystem()
{
}

//Component System
bool CameraSystem::Init(GameEngine& gameEngine)
{
    EntityManager& entityManager = gameEngine.GetEntityManager();
    gameEngine.AddEventListener(this);

	m_resolution = gameEngine.GetConfiguration().GetLogicalResolution();

    m_pGaulemCamera = entityManager.CreateAndAddEntity("GaulemCamera");  
    m_pGaulemCameraComponent = static_cast<CameraComponent*>(m_pGaulemCamera->AddComponent(make_unique<CameraComponent>()));

    m_pBaseCamera = entityManager.CreateAndAddEntity("BaseCamera");
    m_pBaseCameraComponent = static_cast<CameraComponent*>(m_pBaseCamera->AddComponent(make_unique<CameraComponent>()));

    CameraHelper::SetCameras(m_pGaulemCameraComponent, m_pBaseCameraComponent);

    InputManager::AddMouseListener(this, "CameraSystemMouseListener");

    return true;
}

void CameraSystem::PreUpdate(ZeEngine::GameEngine& gameEngine)
{
}

bool CameraSystem::Update(ZeEngine::GameEngine& gameEngine)
{
    UpdateBaseCamera();

    if (m_pGaulemEntity)
    {
        //Follow the Gaulem and set the camera position
        const auto pTransformComponent = m_pGaulemEntity->GetComponent<TransformComponent>();
        if (pTransformComponent)
        {
            const Vector2D<float> position = pTransformComponent->GetPosition() - m_pGaulemCameraComponent->GetPosition();

            if (position.GetX() > m_resolution.GetX())
            {
               //m_pGaulemCameraComponent->SetPosition(pTransformComponent->GetPosition());
            }
        }
    }
    return false;
}

void CameraSystem::UpdateBaseCamera()
{
    m_pBaseCameraComponent->SetDeltaPosition(m_fMouseRelative);

    s32 maxX = (World::cWorldWidth * TileComponent::cTileWidth) - m_resolution.GetX();
    s32 maxY = (World::cWorldHeight * TileComponent::cTileHeight) - m_resolution.GetY();

	if (m_pBaseCameraComponent->GetPosition().GetY() > maxY)
    {
		m_pBaseCameraComponent->SetY(maxY);
    }
	if (m_pBaseCameraComponent->GetPosition().GetX() > maxX)
    {
		m_pBaseCameraComponent->SetX(maxX);
    }
    if (m_pBaseCameraComponent->GetPosition().GetX() < 0)
    {
        m_pBaseCameraComponent->SetX(0);
    }
    if (m_pBaseCameraComponent->GetPosition().GetY() < 0)
    {
        m_pBaseCameraComponent->SetY(0);
    }

	//Give it a smooth feel
    m_fMouseRelative /= 1.75;
}

void CameraSystem::PostUpdate(ZeEngine::GameEngine& gameEngine)
{
}

void CameraSystem::Destroy(ZeEngine::GameEngine& gameEngine)
{
    EntityManager& entityManager = gameEngine.GetEntityManager();
    InputManager::RemoveMouseListener("CameraSystemMouseListener");
    gameEngine.RemoveEventListener(this);
}

bool CameraSystem::HandleEvent(const Event& evt)
{
    switch (evt.GetEventType())
    {
    case Event::eEntityEvent:
        auto pEvent = evt.GetEvent<EntityEvent>();

        if (pEvent)
        {
            if (m_pGaulemEntity == nullptr)
            {
                if (pEvent->IsEntityAdded())
                {
                    Entity& entity = pEvent->GetEntity();

                    if (entity.GetName() == "Gaulem")
                    {
                        m_pGaulemEntity = &entity;
                    }
                }
            }
        }
        break;
    }
    return false;
}

bool CameraSystem::OnMouseMoved( const Vector2D<s32>& absolute, const Vector2D<s32>& relative )
{
    if (m_fDragging)
    {
        //Give it a lilly bit of acceleration
        m_fMouseRelative += (Vector2D<f32>(static_cast<f32>(-relative.GetX()), static_cast<f32>(-relative.GetY())) / 2);
    }

    return false;
}

bool CameraSystem::OnMouseButtonPressed(const Vector2D<s32>& absolute, s32 button)
{
    if (IsLeftButton(button))
    {
        if (!CameraHelper::IsOnTop(absolute, m_resolution))
        {
            m_fDragging = true;
        }
    }

    return false;
}

bool CameraSystem::OnMouseButtonReleased(const Vector2D<s32>& absolute, s32 button)
{
    if (IsLeftButton(button))
    {
        m_fDragging = false;
    }

    return false;
}

const Vector2D<s32>& CameraSystem::GetCameraPosition(bool fTop)
{
	if (fTop)
	{
		return m_pGaulemCameraComponent->GetPosition();
	}
	
	else
	{
		return m_pBaseCameraComponent->GetPosition();
	}
}
